package columnd

import (
	"github.com/pkg/errors"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/common"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
)

func initColumn(d ddd.Domain, repo ColumnRepo) {
	car := &columnAggregateRoot{}
	car.Init(car, d, EvtTypColumn)
	repo.Init(repo, car, EvtTypColumn)

}

// ColumnAggregateRoot 信息的聚合根
type ColumnAggregateRoot interface {
	ddd.AggregateRoot
	// 新增信息
	AddColumn(ctx ddd.Context, column ColumnDesc) (id string, err error)
	// 获取指定信息：根据唯一标识获取信息实体
	GetColumn(ctx ddd.Context, id string) (ia *ColumnAggregate, err error)
	// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
	// total 总数量
	QueryPage(ctx ddd.Context, is ColumnSearch, pi common.PageInfo) (npi common.PageResult, result []ColumnAggregate, err error)
	// 获取系统的栏目树
	ColumnTreeForSys(ctx ddd.Context) (result []ColumnAggregate, err error)
	// 获取组织的栏目树
	ColumnTreeForOrg(ctx ddd.Context, org string) (result []ColumnAggregate, err error)
	// 获取所有者的栏目树
	ColumnTreeForOwner(ctx ddd.Context, owner string) (result []ColumnAggregate, err error)
	// 获取系统开放给组织的所有栏目
	ColumnSysOrgTree(ctx ddd.Context) (result []ColumnAggregate, err error)
	// ExistNameByDesc 判断是否存在同级的相同栏目名的栏目
	// desc Org Owner 为空，栏目范围 平台栏目
	// 		Org Owner 任意不为空，指定组织的栏目或指定所有者的栏目
	// columnid 排除指定的栏目
	// desc.ParentID 指定上级栏目
	// desc.ParentID 为空上级栏目为空，判断最顶级栏目
	// ok true 存在 false 存在
	// err 不等于nil查询失败
	ExistNameByDesc(ctx ddd.Context, columnid string, desc ColumnDesc) (ok bool, err error)
}

// ColumnRepo 信息仓储
type ColumnRepo interface {
	ddd.Repository
	// 新增信息
	AddColumn(ctx ddd.Context, column ColumnDesc) (id string, err error)
	// 获取指定信息：根据唯一标识获取信息实体
	GetColumn(ctx ddd.Context, columnid string) (*ColumnAggregate, error)
	// 分页获取栏目列表：根据唯一标识获取下一页指定数量的信息实体集合
	// total 总数量
	QueryPage(ctx ddd.Context, is ColumnSearch, pi common.PageInfo) (npi common.PageResult, result []ColumnAggregate, err error)
	// 删除信息 标记删除
	DeleteColumn(ctx ddd.Context, columnid string) error
	// 修改信息描述
	UpdateDesc(ctx ddd.Context, columnid string, column *ColumnDesc) error
	// 修改控制参数
	UpdateCtlParam(ctx ddd.Context, columnid string, column *ColumnCtlParam) error

	// 改变栏目包含的信息数量
	// num 大于0增加数量 小于0 减少数量 ，最终值最小为0
	UpdateInfoNum(ctx ddd.Context, columnid string, num int) error
	// 改变栏目包含的发布信息数量
	UpdatePubInfoNum(ctx ddd.Context, columnid string, num int) error
	// 改变栏目包含的发布信息数量
	// 同时更新 信息数量
	UpdatePubInfoNum2(ctx ddd.Context, columnid string, num int) error
	// 修改信息扩展信息
	UpdateExtras(ctx ddd.Context, columnid string, column []ColumnExtraItem) error
	// 锁定栏目
	Lock(ctx ddd.Context, columnid string) error
	// 解锁栏目
	UnLock(ctx ddd.Context, columnid string) error
	// 删除指定栏目
	DeleteByID(ctx ddd.Context, columnid string) error
	// 恢复栏目
	Recover(ctx ddd.Context, columnid string) error
	// 彻底删除指定栏目
	DestroyByID(ctx ddd.Context, columnid string) error
	// 获取系统栏目　或　用户栏目或组织栏目
	ColumnTree(ctx ddd.Context, org, owner string) (result []ColumnAggregate, err error)
	// 获取开放给组织的系统栏目
	ColumnSysOrgTree(ctx ddd.Context) (result []ColumnAggregate, err error)
	// ExistNameByDesc 判断是否存在同级的相同栏目名的栏目
	// org 不为空，栏目范围 组织栏目
	// owner 不为空，栏目范围指定所有者的栏目
	// org 和owner都为空 则平台栏目
	// columnid 排除指定的栏目
	// parentID 指定上级栏目
	// parentID 为空上级栏目为空，判断最顶级栏目
	// ok true 存在 false 存在
	// err 不等于nil查询失败
	ExistName(ctx ddd.Context, org, owner, parentID, columnid, name string) (ok bool, err error)
	// 获取栏目的子栏目列表
	Children(ctx ddd.Context, columnid string) (result []ColumnAggregate, err error)
	// 是否存在子栏目
	ExistChildren(ctx ddd.Context, columnid string) (ok bool, err error)
}

var _ ddd.Aggregate = &ColumnAggregate{}

// ColumnKind 栏目种类
type ColumnKind int

//0,普通栏目[^kind0] 1 系统栏目[^kind1] 2 专题栏目[^kind2] 3 交流互动[^kind3]
const (
	// ColumnKindCommon 普通栏目
	ColumnKindCommon ColumnKind = 0
	// ColumnKindSys 系统栏目
	ColumnKindSys ColumnKind = 1
	// ColumnKindSpe 专题栏目
	ColumnKindSpe ColumnKind = 2
	// ColumnKindInteractive 交流互动
	ColumnKindInteractive ColumnKind = 3
)

// ColumnAggregate 信息聚合
type ColumnAggregate struct {
	ddd.BaseAggregate `json:"-"`
	ColumnID          string             `json:"column_id"` // 唯一标识
	ColumnDesc        `json:"desc"`      // 描述
	ColumnStatus      `json:"status"`    // 状态
	ColumnCtlParam    `json:"ctl_param"` // 控制参数
	common.Operator   `json:"operator"`  // 操作者
	Extras            []ColumnExtraItem  `json:"extras"` // 扩展
}

// Repo 获取聚合根对应的仓储
func (c *ColumnAggregate) Repo() ColumnRepo {
	return c.Repository().(ColumnRepo)
}

// UpdateDesc 修改栏目中的信息描述
func (c *ColumnAggregate) UpdateDesc(ctx ddd.Context, column *ColumnDesc) error {
	if c.Status == CStatusLock {
		return errors.Errorf("栏目已经锁定不能修改")
	}
	err := c.Repo().UpdateDesc(ctx, c.ColumnID, column)
	if err != nil {
		return err
	}
	c.Trigger(ctx, EvtTypColumn, EvtActUpdateDesc, map[string]interface{}{
		"columnid": c.ColumnID,
		"old":      c.ColumnDesc,
		"new":      column,
	})
	return err
}

// UpdateCtlParam 修改栏目中的控制参数
func (c *ColumnAggregate) UpdateCtlParam(ctx ddd.Context, column *ColumnCtlParam) error {
	if c.Status == CStatusLock {
		return errors.Errorf("栏目已经锁定不能修改")
	}
	err := c.Repo().UpdateCtlParam(ctx, c.ColumnID, column)
	if err != nil {
		return err
	}
	old := c.ColumnCtlParam
	c.Trigger(ctx, EvtTypColumn, EvtActUpdateCtl, map[string]interface{}{
		"columnid": c.ColumnID,
		"old":      &old,
		"new":      column,
	})
	return err
}

// UpdateExtras 修改栏目中的扩展属性
func (c *ColumnAggregate) UpdateExtras(ctx ddd.Context, column []ColumnExtraItem) error {
	if c.Status == CStatusLock {
		return errors.Errorf("栏目已经锁定不能修改")
	}
	err := c.Repo().UpdateExtras(ctx, c.ColumnID, column)
	if err != nil {
		return err
	}
	c.Trigger(ctx, EvtTypColumn, EvtActUpdateExtras, map[string]interface{}{
		"columnid": c.ColumnID,
		"old":      c.ColumnDesc,
		"new":      column,
	})
	return err
}

// LockColumn 锁定栏目
func (c *ColumnAggregate) LockColumn(ctx ddd.Context) error {
	if c.Status == CStatusNormal {
		return c.Repo().Lock(ctx, c.ColumnID)
	}
	return errors.Errorf("栏目状态不对不能锁定")
}

// UnLockColumn 解锁栏目
func (c *ColumnAggregate) UnLockColumn(ctx ddd.Context) error {
	if c.Status == CStatusLock {
		return c.Repo().UnLock(ctx, c.ColumnID)
	}
	return errors.Errorf("栏目状态不对不能解锁")
}

// Delete 删除栏目
func (c *ColumnAggregate) Delete(ctx ddd.Context) error {
	if c.Status == CStatusLock {
		return errors.Errorf("栏目已经锁定不能删除")
	}
	err := c.Repo().DeleteByID(ctx, c.ColumnID)
	if err != nil {
		return err
	}
	c.Trigger(ctx, EvtTypColumn, EvtActDelete, c.ColumnDesc)
	return err
}

// Destroy 彻底删除栏目
func (c *ColumnAggregate) Destroy(ctx ddd.Context) error {
	if c.Status == CStatusLock {
		return errors.Errorf("栏目已经锁定不能销毁")
	}
	if c.Status != CStatusDelete {
		return errors.Errorf("只有已删除栏目才可以彻底删除")
	}
	err := c.Repo().DestroyByID(ctx, c.ColumnID)
	if err != nil {
		return err
	}
	c.Trigger(ctx, EvtTypColumn, EvtActDestroy, c.ColumnDesc)
	return err
}

// Recover 恢复栏目
func (c *ColumnAggregate) Recover(ctx ddd.Context) error {
	if c.Status != CStatusDelete {
		return errors.Errorf("只有已删除栏目才可以恢复")
	}
	err := c.Repo().Recover(ctx, c.ColumnID)
	if err != nil {
		return err
	}
	c.Trigger(ctx, EvtTypColumn, EvtActDestroy, c.ColumnDesc)
	return err
}

// Children 获取栏目的子栏目
func (c *ColumnAggregate) Children(ctx ddd.Context) ([]ColumnAggregate, error) {
	return c.Repo().Children(ctx, c.ColumnID)
}

// ExistChildren 是否存在子栏目
func (c *ColumnAggregate) ExistChildren(ctx ddd.Context) (bool, error) {
	return c.Repo().ExistChildren(ctx, c.ColumnID)
}

// UpdatePubInfoNum 栏目信息发布数量+num
func (c *ColumnAggregate) UpdatePubInfoNum(ctx ddd.Context, num int) error {
	return c.Repo().UpdatePubInfoNum(ctx, c.ColumnID, num)
}

// UpdatePubInfoNum2 栏目信息发布数量+num
func (c *ColumnAggregate) UpdatePubInfoNum2(ctx ddd.Context, num int) error {
	return c.Repo().UpdatePubInfoNum2(ctx, c.ColumnID, num)
}

// UpdateInfoNum 更新栏目信息数量+num
func (c *ColumnAggregate) UpdateInfoNum(ctx ddd.Context, num int) error {
	return c.Repo().UpdateInfoNum(ctx, c.ColumnID, num)
}

var (
	_ ColumnAggregateRoot = &columnAggregateRoot{}
)

type columnAggregateRoot struct {
	ddd.BaseAggregateRoot
}

func (c *columnAggregateRoot) Repo() ColumnRepo {
	return c.Repository().(ColumnRepo)
}
func (c *columnAggregateRoot) AddColumn(ctx ddd.Context, column ColumnDesc) (id string, err error) {
	return c.Repo().AddColumn(ctx, column)
}
func (c *columnAggregateRoot) GetColumn(ctx ddd.Context, id string) (ia *ColumnAggregate, err error) {
	return c.Repo().GetColumn(ctx, id)
}

// 分页获取信息列表：根据唯一标识获取下一页指定数量的信息实体集合
// total 总数量
func (c *columnAggregateRoot) QueryPage(ctx ddd.Context, is ColumnSearch, pi common.PageInfo) (npi common.PageResult, result []ColumnAggregate, err error) {
	return c.Repo().QueryPage(ctx, is, pi)

}
func (c *columnAggregateRoot) ColumnTreeForSys(ctx ddd.Context) (result []ColumnAggregate, err error) {
	return c.Repo().ColumnTree(ctx, "", "")
}
func (c *columnAggregateRoot) ColumnTreeForOrg(ctx ddd.Context, org string) (result []ColumnAggregate, err error) {
	return c.Repo().ColumnTree(ctx, org, "")
}
func (c *columnAggregateRoot) ColumnTreeForOwner(ctx ddd.Context, owner string) (result []ColumnAggregate, err error) {
	return c.Repo().ColumnTree(ctx, "", owner)
}
func (c *columnAggregateRoot) ColumnSysOrgTree(ctx ddd.Context) (result []ColumnAggregate, err error) {
	return c.Repo().ColumnSysOrgTree(ctx)
}

// ExistNameByDesc 判断是否存在同级的相同栏目名的栏目
// desc Org Owner 为空，栏目范围 平台栏目
// 		Org Owner 任意不为空，指定组织的栏目或指定所有者的栏目
// columnid 排除指定的栏目
// desc.ParentID 指定上级栏目
// desc.ParentID 为空上级栏目为空，判断最顶级栏目
// ok true 存在 false 存在
// err 不等于nil查询失败
func (c *columnAggregateRoot) ExistNameByDesc(ctx ddd.Context, columnid string, desc ColumnDesc) (ok bool, err error) {
	return c.Repo().ExistName(ctx, desc.Org, desc.Owner, desc.ParentID, columnid, desc.Name)
}
